

#include "ly/export.hpp"
#include "ly/pcell_declaration.hpp"
#include "ly/pcell_header.hpp"
#include "ly/variant.hpp"

#include <map>
#include <string>
#include <vector>

namespace ly {

/**
 *  @brief A PCell variant
 */
class LY_API PCellVariant : public ly::Cell {
 public:
  PCellVariant() {};
  PCellVariant(ly::cell_id_type cell_id, ly::Layout::sptr layout, ly::pcell_id_type pcell_id, const pcell_parameters_type& parameters);

  /**
   *  @brief The destructor
   */
  ~PCellVariant() {};

  template <typename... Args>
  static cell_sptr create(Args&&... args) {
    return std::make_shared<PCellVariant>(std::forward<Args>(args)...);
  }

  // /**
  //  *  @brief Cloning
  //  */
  // virtual Cell* clone(Layout& layout) const;

  /**
   *  @brief Gets the parameter name map for a parameter list
   */
  std::map<std::string, ly::Variant> parameters_by_name_from_list(const pcell_parameters_type& list) const;

  /**
   *  @brief Gets the parameter name map for this variant
   */
  std::map<std::string, ly::Variant> parameters_by_name() const;

  /**
   *  @brief Gets the parameter by name for this variant
   *  Returns a nil variant if there is no parameter with that name
   */
  ly::Variant parameter_by_name(const std::string& name) const;

  /**
   *  @brief Gets the parameters for this variant
   */
  const std::vector<ly::Variant>& parameters() const { return m_parameters; }

  /**
   *  @brief Get the PCell Id for this variant
   */
  ly::pcell_id_type pcell_id() const { return m_pcell_id; }

  // /**
  //  *  @brief Get the basic name
  //  *
  //  *  The basic name of the cell is either the cell name or the cell name in the
  //  *  target library (for library proxies) or the PCell name (for PCell proxies).
  //  *  The actual name may be different by a extension to make it unique.
  //  */
  // virtual std::string get_basic_name() const;

  /**
   *  @brief Get the display name
   *
   *  The display name is some "nice" descriptive name of the cell (variant)
   *  For normal cells this name is equivalent to the normal cell name.
   */
  virtual std::string get_display_name() const;

  /**
   *  @brief Unregister a cell from it's context.
   */
  virtual void unregister();

  /**
   *  @brief Reregister a cell inside it's context.
   */
  virtual void reregister();

  /**
   *  @brief Update the layout
   */
  // virtual void update(ImportLayerMapping* layer_mapping = 0);

  /**
   *  @brief Tell, if this cell is a proxy cell
   *
   *  Proxy cells are such whose layout represents a snapshot of another entity.
   *  Such cells can be PCell variants or library references for example.
   */
  virtual bool is_proxy() const { return true; }

 protected:
  /**
   *  @brief Get the PCell header for this variant
   */
  PCellHeader::sptr pcell_header() { return layout()->pcell_header(m_pcell_id); }

  /**
   *  @brief Get the PCell header for this variant
   */
  // const PCellHeader::sptr pcell_header() const { return layout()->pcell_header(m_pcell_id); }

 private:
  pcell_parameters_type m_parameters;
  mutable std::string m_display_name;
  ly::pcell_id_type m_pcell_id;
  bool m_registered;
};

}  // namespace ly
